/* 
 * File: abstracttablemodel.h
 * Project: QTimeTracker
 * Author: Steve Sindelar, http://stevesindelar.cz
 * Licence: NewBSD licence.
 */

#ifndef ABSTRACTTABLEMODEL_H
#define ABSTRACTTABLEMODEL_H

#include <QAbstractTableModel>
#include "tablemodelcolumn.h"

namespace Ui
{

	/**
	 * Base class for table models, it uses TableModelColumn for columns representation.
	 * This class delegates most of the QAbstractTableModel work to columns instances, 
	 * this reduces need for long switch statements in methods of QAbstractTableModel based classes.
	 * 
	 * Overriden methods are not documented since they might be found in Qt docs.
	 */
	class AbstractTableModel : public QAbstractTableModel
	{
		Q_OBJECT

	protected:
		AbstractTableModel(){}

	signals:
		/**
		 * This signal is emited when the data of this model has been changed 
		 * thru editation. That means that method setData has been called.
		 */
		void dataEdited();

	public:

		/**
		 * Returns count of row elements in model, this is the only pure virtual method.
		 */
		int rowCount(const QModelIndex & parent = QModelIndex()) const = 0;

		inline int columnCount(const QModelIndex &parent = QModelIndex()) const
		{
			return this->columns.size();
		}

		inline QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
		{
			if (!index.isValid()) 
			{
				return QVariant();
			}

			if (role == Qt::DisplayRole)
			{
				return this->columns[index.column()]->getDataForDisplayRole(index);
			}
			else if (role == Qt::EditRole)
			{
				return this->columns[index.column()]->getDataForEditRole(index);
			}

			return QVariant();
		}

		inline QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const
		{
			if (role != Qt::DisplayRole)
			{
				return QVariant();
			}

			if (section >= this->columns.size()) 
			{
				return QVariant();
			}

			return this->columns[section]->getHeader();
		}

		inline bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
		{
			if (!index.isValid()) 
			{
				return false;
			}

			bool result = this->columns[index.column()]->setData(index, value);
			emit this->dataChanged(this->createIndex(index.row(),0), this->createIndex(index.row(), this->columnCount()-1));
			emit this->dataEdited();

			return result;
		}

		/**
		 * Helper method, emits layout changed signal of QAbstractTableModel.
		 */
		inline void emitLayoutChanged()
		{
			emit this->layoutChanged();
		}
		
		/**
		 * Helper method, emits custom signal 'dataChanged'.
		 */
		inline void emitDataChanged(int row)
		{
			emit this->dataChanged(this->createIndex(row, 0), this->createIndex(row, this->columnCount()-1));
		}

		inline Qt::ItemFlags flags(const QModelIndex & index) const 
		{
			if (!index.isValid()) 
			{
				return 0;
			}

			return this->columns[index.column()]->getFlags(index);
		}

		/**
		 * Adds column instance.
		 * Column is responsible for providing information such as header, data as certain row index, ...
		 */
		inline void addColumn(TableModelColumn *column)
		{
			this->columns.push_back(column);
		}

		virtual ~AbstractTableModel() {};

	private:
		/**
		 * List of columns that handles all the QAbstractTable work, which is delegated to them.
		 */
		QList<TableModelColumn*> columns;
	};

} //namespace

#endif // ABSTRACTTABLEMODEL_H
